package very.util.response

import org.json4s.Formats
import org.json4s.native.Serialization.write
import play.api.mvc._
import ws.very.util.json.{JsonHelper, JsonHelperWithDoubleMode}

import scala.util.{Failure, Success, Try}

trait Invalid {
  def errorMsg: String
}
//"JSON 注入问题"
trait ResponseFormat extends JsonHelper {

  import Results._

  val OkResponse = Ok("""{"isOk":true}""")

  def BooleanResponse(res: Boolean) = Ok(toJson(("isOk" -> true) ~ ("data" -> res)))

  def StrResponse(res: String) = Ok(toJson(("isOk" -> true) ~ ("data" -> res)))

  def NumResponse(res: BigDecimal) = Ok(toJson(("isOk" -> true) ~ ("data" -> res)))

  def errorResponse(error: String) = Ok(toJson(("isOk" -> false) ~ ("message" -> error)))

  implicit def eitherToResponse[R, L](result: Either[R, L]): Result = {
    result match {
      case Right(v: String) =>
        StrResponse(v)
      case Right(v: Result) =>
        v
      case Right(value: Iterable[_]) => collectionToResponse(value)
      case Right(value: Option[_])   => optionToResponse(value)
      case Right(Unit)               => OkResponse
      case Right(v) =>
        Ok(s"""{"isOk":true,"data":${write(v)}}""")
      case Left(v: String) =>
        errorResponse(v)
      case Left(v: Invalid) =>
        errorResponse(v.errorMsg)
      case _ =>
        errorResponse("Server Error")
    }
  }
  implicit def tryToResponse[T](result: Try[T]): Result = {
    eitherToResponse(result match {
      case Success(v) => Right(v)
      case Failure(e) => Left(e.getMessage)
    })
  }

  implicit def optionToResponse[T](value: Option[T]): Result = {
    value match {
      case Some(v: String)     => StrResponse(v)
      case Some(v: BigDecimal) => NumResponse(v)
      case Some(Unit)          => OkResponse
      case Some(v)             => Ok(s"""{"isOk":true,"data":${write(v)}}""")
      case None =>
        errorResponse("不存在")
    }
  }

  implicit def collectionToResponse[T](result: Iterable[T]): Result = {
    Ok(s"""{"isOk":true,"data":${write(result)}}""")
  }

  implicit def StringToResponse(str: String): Result = {
    StrResponse(str)
  }
}

object ResponseFormat extends ResponseFormat with JsonHelperWithDoubleMode {
  implicit override val formats: Formats =
    org.json4s.DefaultFormats ++ org.json4s.ext.JodaTimeSerializers.all
}
